package com.faner4cloud.yun.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.faner4cloud.yun.common.constant.CacheConstants;
import com.faner4cloud.yun.common.exception.BizException;
import com.faner4cloud.yun.common.redis.RedisLock;
import com.faner4cloud.yun.common.util.R;
import com.faner4cloud.yun.dao.entity.SysDict;
import com.faner4cloud.yun.dao.entity.SysDictItem;
import com.faner4cloud.yun.service.SysDictItemService;
import com.faner4cloud.yun.service.SysDictService;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;

/**
 * @author ...zz
 * @version v1
 * @summary desc
 * @since 2022/7/8 4:24 PM
 */
@Slf4j
@RestController
@RequestMapping("/dict")
@RequiredArgsConstructor
public class DictController {

	private final SysDictItemService sysDictItemService;

	private final SysDictService sysDictService;

	private final Cache<String, Object> caffeineCache;

	private final RedisLock redisLock;


	/**
	 * 通过ID查询字典信息
	 * @param id ID
	 * @return 字典信息
	 */
	@GetMapping("/{id:\\d+}")
	public R<SysDict> getById(@PathVariable Long id) {
		String key = "sysdict:"+id;
		Object value = caffeineCache.getIfPresent(key);
		log.warn("从本地缓存中获取数据 key {}，value {}", key, value);

		if (value != null) {
			if (CacheConstants.EMPTY_CACHE.equals(value)){
				return null;
			}
			return R.ok((SysDict) value);
		}
		if (!redisLock.lock(key)) {
			log.info("缓存数据为空，从数据库查询菜谱信息时获取锁失败，dictId:{}", id);
			throw new BizException("系统繁忙，请稍后重试");
		}
		try{
			// 缓存中没有数据，则查询数据库，并将结果放至数据库
			SysDict sysDict = sysDictService.getById(id);
			caffeineCache.put(key, Objects.isNull(sysDict) ? CacheConstants.EMPTY_CACHE : sysDict);
			return R.ok(sysDict);
		}finally {
			redisLock.unlock(key);
		}
	}

	/**
	 * 分页查询字典信息
	 * @param page 分页对象
	 * @return 分页对象
	 */
	@GetMapping("/page")
	public R<IPage<SysDict>> getDictPage(Page page, SysDict sysDict) {
		return R.ok(sysDictService.page(page, Wrappers.query(sysDict)));
	}

	/**
	 * 通过字典类型查找字典
	 * @param type 类型
	 * @return 同类型字典
	 */
	@GetMapping("/type/{type}")
	@Cacheable(value = CacheConstants.DICT_DETAILS, key = "#type")
	public R<List<SysDictItem>> getDictByType(@PathVariable String type) {
		return R.ok(sysDictItemService.list(Wrappers.<SysDictItem>query().lambda().eq(SysDictItem::getType, type)));
	}

	/**
	 * 添加字典
	 * @param sysDict 字典信息
	 * @return success、false
	 */
	@PostMapping
	public R<Boolean> save(@Valid @RequestBody SysDict sysDict) {
		return R.ok(sysDictService.save(sysDict));
	}

	/**
	 * 删除字典，并且清除字典缓存
	 * @param id ID
	 * @return R
	 */
	@DeleteMapping("/{id:\\d+}")
	public R removeById(@PathVariable Long id) {
		sysDictService.removeDict(id);
		return R.ok();
	}

	/**
	 * 修改字典
	 * @param sysDict 字典信息
	 * @return success/false
	 */
	@PutMapping
	public R updateById(@Valid @RequestBody SysDict sysDict) {
		sysDictService.updateDict(sysDict);
		return R.ok();
	}

	/**
	 * 分页查询
	 * @param page 分页对象
	 * @param sysDictItem 字典项
	 * @return
	 */
	@GetMapping("/item/page")
	public R<IPage<SysDictItem>> getSysDictItemPage(Page page, SysDictItem sysDictItem) {
		return R.ok(sysDictItemService.page(page, Wrappers.query(sysDictItem)));
	}

	/**
	 * 通过id查询字典项
	 * @param id id
	 * @return R
	 */
	@GetMapping("/item/{id:\\d+}")
	public R<SysDictItem> getDictItemById(@PathVariable("id") Long id) {
		return R.ok(sysDictItemService.getById(id));
	}

	/**
	 * 新增字典项
	 * @param sysDictItem 字典项
	 * @return R
	 */
	@PostMapping("/item")
	@CacheEvict(value = CacheConstants.DICT_DETAILS, allEntries = true)
	public R<Boolean> save(@RequestBody SysDictItem sysDictItem) {
		return R.ok(sysDictItemService.save(sysDictItem));
	}

	/**
	 * 修改字典项
	 * @param sysDictItem 字典项
	 * @return R
	 */
	@PutMapping("/item")
	public R updateById(@RequestBody SysDictItem sysDictItem) {
		sysDictItemService.updateDictItem(sysDictItem);
		return R.ok();
	}

	/**
	 * 通过id删除字典项
	 * @param id id
	 * @return R
	 */
	@DeleteMapping("/item/{id:\\d+}")
	public R removeDictItemById(@PathVariable Long id) {
		sysDictItemService.removeDictItem(id);
		return R.ok();
	}

	@DeleteMapping("/cache")
	public R clearDictCache() {
		sysDictService.clearDictCache();
		return R.ok();
	}

}
